home *** CD-ROM | disk | FTP | other *** search
- #include <pragma/dos_lib.h>
- #include <pragma/exec_lib.h>
- #include <libraries/asyncio.h>
- #include <exec/memory.h>
- #include <string.h>
-
- #define D_S(type,name) char a_##name[ sizeof( type )+3]; type *name=(type *)((LONG)(a_##name+3)&~3);
-
- #ifndef MIN
- #define MIN(a,b) ((a)<(b)?(a):(b))
- #endif
-
- static VOID AS_SendPacket(struct AsyncFile *file,APTR arg2)
- {
- file->af_Packet.sp_Pkt.dp_Port=&file->af_PacketPort;
- file->af_Packet.sp_Pkt.dp_Arg2=(LONG)arg2;
- PutMsg(file->af_Handler,&file->af_Packet.sp_Msg);
- file->af_PacketPending=TRUE;
- }
-
- static LONG AS_WaitPacket(AsyncFile *file)
- {
- LONG bytes;
- if(file->af_PacketPending)
- {
- while(TRUE)
- {
- file->af_PacketPort.mp_Flags=PA_SIGNAL;
- Remove((struct Node *)WaitPort(&file->af_PacketPort));
- file->af_PacketPort.mp_Flags=PA_IGNORE;
- file->af_PacketPending=FALSE;
- bytes=file->af_Packet.sp_Pkt.dp_Res1;
- if(bytes>=0) return bytes;
- if(ErrorReport(file->af_Packet.sp_Pkt.dp_Res2,REPORT_STREAM,file->af_File,NULL)) return -1;
- AS_SendPacket(file,file->af_Buffers[file->af_ReadMode?file->af_CurrentBuf:1-file->af_CurrentBuf]);
- }
- }
- SetIoErr(file->af_Packet.sp_Pkt.dp_Res2);
- return file->af_Packet.sp_Pkt.dp_Res1;
- }
-
- static VOID AS_RecordSyncFailure(struct AsyncFile *file)
- {
- file->af_LastRes1=file->af_Packet.sp_Pkt.dp_Res1;
- file->af_LastBytesLeft=file->af_BytesLeft;
- file->af_Packet.sp_Pkt.dp_Res1=-1;
- file->af_Packet.sp_Pkt.dp_Res2=IoErr();
- file->af_BytesLeft=0;
- }
-
- static VOID AS_RequeuePacket(AsyncFile *file)
- {
- AddHead(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node);
- file->af_PacketPending=TRUE;
- }
-
- AsyncFile *AS_OpenAsyncFH(BPTR handle,LONG mode,LONG bufferSize,BOOL closeIt)
- {
- FileHandle *fh;
- AsyncFile *file=NULL;
- BPTR lock=NULL;
- LONG blockSize,blockSize2;
- D_S(struct InfoData,infoData);
- if(mode==MODE_READ)
- {
- if(handle) lock=DupLockFromFH(handle);
- }
- else
- {
- if(mode==MODE_APPEND)
- {
- if(handle)
- {
- if(Seek(handle,0,OFFSET_END)<0)
- {
- if(closeIt) Close(handle);
- handle=NULL;
- }
- }
- }
- if(handle) lock=ParentOfFH(handle);
- }
- if(handle)
- {
- blockSize=512;
- blockSize2=1024;
- if(lock)
- {
- if(Info(lock,infoData))
- {
- blockSize=infoData->id_BytesPerBlock;
- blockSize2=blockSize*2;
- bufferSize=((bufferSize+blockSize2-1)/blockSize2)*blockSize2;
- }
- UnLock(lock);
- }
- for(;;)
- {
- if(file=(AsyncFile *)AllocVec(sizeof(AsyncFile)+bufferSize+15,MEMF_PUBLIC|MEMF_ANY)) break;
- else
- {
- if(bufferSize>blockSize2)bufferSize-=blockSize2;
- else break;
- }
- }
- if(file)
- {
- file->af_File=handle;
- file->af_ReadMode=(mode==MODE_READ);
- file->af_BlockSize=blockSize;
- file->af_CloseFH=closeIt;
- fh=(FileHandle *)BADDR(file->af_File);
- file->af_Handler=fh->fh_Type;
- file->af_BufferSize=(ULONG)bufferSize/2;
- file->af_Buffers[0]=(UBYTE *)(((ULONG)file+sizeof(AsyncFile)+15)&0xfffffff0);
- file->af_Buffers[1]=file->af_Buffers[0]+file->af_BufferSize;
- file->af_CurrentBuf=0;
- file->af_SeekOffset=0;
- file->af_PacketPending=FALSE;
- file->af_SeekPastEOF=FALSE;
- file->af_PacketPort.mp_MsgList.lh_Head=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Tail;
- file->af_PacketPort.mp_MsgList.lh_Tail=NULL;
- file->af_PacketPort.mp_MsgList.lh_TailPred=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Head;
- file->af_PacketPort.mp_Node.ln_Type=NT_MSGPORT;
- file->af_PacketPort.mp_Node.ln_Name=NULL;
- file->af_PacketPort.mp_Flags=PA_IGNORE;
- file->af_PacketPort.mp_SigBit=SIGB_SINGLE;
- file->af_PacketPort.mp_SigTask=FindTask(NULL);
- file->af_Packet.sp_Pkt.dp_Link=&file->af_Packet.sp_Msg;
- file->af_Packet.sp_Pkt.dp_Arg1=fh->fh_Arg1;
- file->af_Packet.sp_Pkt.dp_Arg3=file->af_BufferSize;
- file->af_Packet.sp_Pkt.dp_Res1=0;
- file->af_Packet.sp_Pkt.dp_Res2=0;
- file->af_Packet.sp_Msg.mn_Node.ln_Name=(STRPTR)&file->af_Packet.sp_Pkt;
- file->af_Packet.sp_Msg.mn_Node.ln_Type=NT_MESSAGE;
- file->af_Packet.sp_Msg.mn_Length=sizeof(struct StandardPacket);
- if(mode==MODE_READ)
- {
- file->af_Packet.sp_Pkt.dp_Type=ACTION_READ;
- file->af_BytesLeft=0;
- file->af_Offset=file->af_Buffers[1];
- if(file->af_Handler) AS_SendPacket(file,file->af_Buffers[0]);
- }
- else
- {
- file->af_Packet.sp_Pkt.dp_Type=ACTION_WRITE;
- file->af_BytesLeft=file->af_BufferSize;
- file->af_Offset=file->af_Buffers[0];
- }
- }
- else
- {
- if(closeIt) Close(handle);
- }
- }
- return file;
- }
-
- struct AsyncFile *OpenAsync(register __a0 STRPTR fileName,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base)
- {
- static const WORD PrivateOpenModes[]={MODE_OLDFILE,MODE_NEWFILE,MODE_READWRITE};
- BPTR handle;
- AsyncFile *file=NULL;
- if(handle=Open(fileName,PrivateOpenModes[mode]))
- {
- if(!(file=AS_OpenAsyncFH(handle,mode,bufferSize,TRUE)))Close(handle);
- }
- return file;
- }
-
- struct AsyncFile *OpenAsyncFromFH(register __a0 BPTR handle,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base)
- {
- return AS_OpenAsyncFH(handle,mode,bufferSize,FALSE);
- }
-
- LONG CloseAsync(register __a0 struct AsyncFile *file,register __a6 struct AsyncIOBase *base)
- {
- LONG result;
- if(file)
- {
- result=AS_WaitPacket(file);
- if(result>=0)
- {
- if(!file->af_ReadMode)
- {
- if(file->af_BufferSize>file->af_BytesLeft)
- {
- result=Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft);
- }
- }
- }
- if(file->af_CloseFH) Close(file->af_File);
- FreeVec(file);
- }
- else result=-1;
- return result;
- }
-
- LONG ReadAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
- {
- LONG totalBytes=0;
- LONG bytesArrived;
- while(numBytes>file->af_BytesLeft)
- {
- CopyMem(file->af_Offset,buffer,file->af_BytesLeft);
- numBytes-=file->af_BytesLeft;
- buffer=(APTR)((ULONG)buffer+file->af_BytesLeft);
- totalBytes+=file->af_BytesLeft;
- file->af_BytesLeft=0;
- bytesArrived=AS_WaitPacket(file);
- if(bytesArrived<=0)
- {
- if(bytesArrived==0) return(totalBytes);
- return -1;
- }
- AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
- if(file->af_SeekOffset>bytesArrived) file->af_SeekOffset=bytesArrived;
- file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+file->af_SeekOffset;
- file->af_CurrentBuf=1-file->af_CurrentBuf;
- file->af_BytesLeft=bytesArrived-file->af_SeekOffset;
- file->af_SeekOffset=0;
- }
- CopyMem(file->af_Offset,buffer,numBytes);
- file->af_BytesLeft-=numBytes;
- file->af_Offset+=numBytes;
- return totalBytes+numBytes;
- }
-
- LONG PeekAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
- {
- if(!file->af_BytesLeft)
- {
- LONG bytes;
- if((bytes=ReadAsync(file,&bytes,1,base))<=0) return bytes;
- --file->af_Offset;
- ++file->af_BytesLeft;
- }
- numBytes=MIN(numBytes,file->af_BytesLeft);
- CopyMem(file->af_Offset,buffer,numBytes);
- return numBytes;
- }
-
- LONG ReadCharAsync(register __a0 AsyncFile *file,register __a6 struct AsyncIOBase *base)
- {
- UBYTE ch;
- if(file->af_BytesLeft)
- {
- ch=*file->af_Offset;
- --file->af_BytesLeft;
- ++file->af_Offset;
- return ch;
- }
- if(ReadAsync(file,&ch,1,base)>0) return ch;
- return -1;
- }
-
- STRPTR FGetsLenAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a2 LONG *len,register __a6 struct AsyncIOBase *base)
- {
- UBYTE *p;
- LONG length=0;
- p=(UBYTE *)buf;
- if(--numBytes<=0) return 0;
- while(TRUE)
- {
- UBYTE *ptr;
- LONG i,count;
- ptr=(UBYTE *)file->af_Offset;
- if(count=file->af_BytesLeft)
- {
- count=MIN(count,numBytes);
- for(i=0;(i<count)&&(*ptr!='\n');++i) *p++=*ptr++;
- length+=i;
- if(i<count)
- {
- *p++='\n';
- ++i;
- length+=1;
- }
- file->af_BytesLeft-=i;
- file->af_Offset+=i;
- if((i>=numBytes)||(*(p-1)=='\n')) break;
- numBytes-=i;
- }
- if(ReadAsync(file,p,1,base)<1) break;
- --numBytes;
- ++length;
- if(*p++=='\n') break;
- }
- *p='\0';
- *len=length;
- if(p==(UBYTE *)buf) return 0;
- return buf;
- }
-
- STRPTR FGetsAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
- {
- LONG len;
- return FGetsLenAsync(file,buf,numBytes,&len,base);
- }
-
- LONG ReadLineAsync(register __a0 AsyncFile *file,register __a1 APTR buffer,register __d0 LONG bufSize,register __a6 struct AsyncIOBase *base)
- {
- LONG len;
- if(FGetsLenAsync(file,buffer,bufSize,&len,base))
- {
- UBYTE *end;
- end=((UBYTE *)buffer)+len-1;
- if(*end!='\n')
- {
- UBYTE ch=0;
- while(TRUE)
- {
- UBYTE *ptr;
- LONG i,count;
- ptr=(UBYTE *)file->af_Offset;
- if(count=file->af_BytesLeft)
- {
- for(i=0;(i<count)&& (*ptr!='\n');++i,++ptr)
- {
- }
- if(i<count)
- {
- ch='\n';
- ++i;
- }
- file->af_BytesLeft-=i;
- file->af_Offset+=i;
- if(i<count) break;
- }
- if(ReadAsync(file,&ch,1,base)<1) break;
- if(ch=='\n') break;
- }
- if(ch=='\n')
- {
- *end++='\n';
- *end='\0';
- }
- }
- }
- return len;
- }
-
- static ULONG GetFileSize(AsyncFile *file,LONG *size)
- {
- D_S(struct FileInfoBlock,fib);
- if(!ExamineFH(file->af_File,fib))
- {
- AS_RecordSyncFailure(file);
- return FALSE;
- }
- *size=fib->fib_Size;
- return TRUE;
- }
-
- LONG SeekAsync(register __a0 struct AsyncFile *file,register __d0 LONG position,register __d1 LONG mode,register __a6 struct AsyncIOBase *base)
- {
- LONG current,target,roundTarget,filePos;
- LONG minBuf,maxBuf,bytesArrived,diff;
- LONG fileSize;
- bytesArrived=AS_WaitPacket(file);
- if(bytesArrived<0)
- {
- if(file->af_SeekPastEOF)
- {
- bytesArrived=file->af_LastRes1;
- file->af_BytesLeft=file->af_LastBytesLeft;
- }
- else return -1;
- }
- if(file->af_ReadMode)
- {
- filePos=Seek(file->af_File,0,OFFSET_CURRENT);
- if(filePos<0)
- {
- AS_RecordSyncFailure(file);
- return -1;
- }
- current=filePos-(file->af_BytesLeft+bytesArrived)+file->af_SeekOffset;
- if(mode==MODE_CURRENT) target=current+position;
- else if(mode==MODE_START) target=position;
- else
- {
- if(!GetFileSize(file,&fileSize)) return -1;
- target=fileSize+position;
- }
- minBuf=current-(LONG)(file->af_Offset-file->af_Buffers[1-file->af_CurrentBuf]);
- maxBuf=current+file->af_BytesLeft+bytesArrived;
- diff=target-current;
- if((target<minBuf)||(target>=maxBuf))
- {
- if(target>=maxBuf)
- {
- if(!GetFileSize(file,&fileSize)) return -1;
- if(target>fileSize)
- {
- file->af_SeekPastEOF=TRUE;
- SetIoErr(ERROR_SEEK_ERROR);
- AS_RecordSyncFailure(file);
- return -1;
- }
- }
- roundTarget=(target/file->af_BlockSize)*file->af_BlockSize;
- if(Seek(file->af_File,roundTarget-filePos,OFFSET_CURRENT)<0)
- {
- AS_RecordSyncFailure(file);
- return -1;
- }
- AS_SendPacket(file,file->af_Buffers[0]);
- file->af_SeekOffset=target-roundTarget;
- file->af_BytesLeft=0;
- file->af_CurrentBuf=0;
- file->af_Offset=file->af_Buffers[1];
- }
- else if((target<current)||(diff<=file->af_BytesLeft))
- {
- AS_RequeuePacket(file);
- file->af_BytesLeft-=diff;
- file->af_Offset+=diff;
- if(file->af_SeekPastEOF) file->af_Packet.sp_Pkt.dp_Res1=file->af_LastRes1;
- }
- else
- {
- AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
- diff-=file->af_BytesLeft-file->af_SeekOffset;
- file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+diff;
- file->af_BytesLeft=bytesArrived-diff;
- file->af_SeekOffset=0;
- file->af_CurrentBuf=1-file->af_CurrentBuf;
- }
- }
- else
- {
- if(file->af_BufferSize>file->af_BytesLeft)
- {
- if(Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft)<0)
- {
- AS_RecordSyncFailure(file);
- return -1;
- }
- }
- current=Seek(file->af_File,position,mode);
- if(current<0)
- {
- AS_RecordSyncFailure(file);
- return -1;
- }
- file->af_BytesLeft=file->af_BufferSize;
- file->af_CurrentBuf=0;
- file->af_Offset=file->af_Buffers[0];
- }
- if(file->af_SeekPastEOF) file->af_SeekPastEOF=FALSE;
- SetIoErr(0);
- return current;
- }
-
- LONG WriteAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base)
- {
- LONG totalBytes=0;
- if(!file->af_Handler)
- {
- file->af_Offset=file->af_Buffers[0];
- file->af_BytesLeft=file->af_BufferSize;
- return numBytes;
- }
- while(numBytes>file->af_BytesLeft)
- {
- if(file->af_BytesLeft)
- {
- CopyMem(buffer,file->af_Offset,file->af_BytesLeft);
- numBytes-=file->af_BytesLeft;
- buffer=(APTR)((ULONG)buffer+file->af_BytesLeft);
- totalBytes+=file->af_BytesLeft;
- }
- if(AS_WaitPacket(file)<0) return -1;
- AS_SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
- file->af_CurrentBuf=1-file->af_CurrentBuf;
- file->af_Offset=file->af_Buffers[file->af_CurrentBuf];
- file->af_BytesLeft=file->af_BufferSize;
- }
- CopyMem(buffer,file->af_Offset,numBytes);
- file->af_BytesLeft-=numBytes;
- file->af_Offset+=numBytes;
- return totalBytes+numBytes;
- }
-
- LONG WriteCharAsync(register __a0 struct AsyncFile *file,register __d0 ULONG ch,register __a6 struct AsyncIOBase *base)
- {
- UBYTE c;
- if(file->af_BytesLeft)
- {
- *file->af_Offset=ch;
- --file->af_BytesLeft;
- ++file->af_Offset;
- return 1;
- }
- c=ch;
- return WriteAsync(file,&c,1,base);
- }
-
- LONG WriteLineAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR line,register __a6 struct AsyncIOBase *base)
- {
- return WriteAsync(file,line,strlen(line),base);
- }
-